home *** CD-ROM | disk | FTP | other *** search
-
- {$I-} { I/O hecking OFF }
- {$R-} { Range checking OFF }
- {$S-} { Stack checking OFF }
- {$V-} { Var-str checking OFF}
- {$B+} {Boolean complete evaluation on}
- {$N-} {No numeric coprocessor}
-
- Unit RS232INT;
-
- Interface
-
- Uses
- Crt,
- Dos;
-
- { global declarations for Async}
-
- type
- astr = String[160]; { generic string type for parameters }
-
- const
- buffer_max = 5120;
-
- var
- Async_OriginalVector : pointer;
- buffer : Array[0..buffer_max] of char;
-
- Async_Open_Flag : Boolean; { true if Open but no Close }
- Async_Port : Integer; { current Open port number (1 or 2) }
- base : Integer; { base for current open port }
- Async_Irq : Integer; { irq for current open port }
-
- Async_Buffer_Overflow : Boolean; { True if buffer overflow has happened }
- Async_Buffer_Used : Integer;
- Async_MaxBufferUsed : Integer;
-
- { buffer is empty if Head = Tail }
- Buffer_head : Integer; { Locn in buffer to put next char }
- Buffer_tail : Integer; { Locn in buffer to get next char }
- Buffer_newtail : Integer;
-
-
- { End of Async declarations }
-
- procedure async_isr; INTERRUPT;
- procedure set_baud(r:integer);
- function charin:char;
- procedure charout(c:char);
- function cdet:boolean;
- procedure Async_Init;
- procedure Async_Close;
- Procedure Async_Open(ComPort : Integer;
- BaudRate : Integer;
- Parity : Char;
- WordSize : Integer;
- StopBits : Integer);
-
- Implementation
-
- const
- UART_THR = $00;
- UART_RBR = $00;
- UART_IER = $01;
- UART_IIR = $02;
- UART_LCR = $03;
- UART_MCR = $04;
- UART_LSR = $05;
- UART_MSR = $06;
-
- I8088_IMR = $21; { port address of the Interrupt Mask Register }
-
-
- var
-
- Async_BIOS_Port_Table : Array[1..4] of Integer absolute $40:0;
-
- const
- Async_Num_Bauds = 8;
- Async_Baud_Table : array [1..Async_Num_Bauds] of record
- Baud, Bits : integer
- end
- = ((Baud:110; Bits:$00),
- (Baud:150; Bits:$20),
- (Baud:300; Bits:$40),
- (Baud:600; Bits:$60),
- (Baud:1200; Bits:$80),
- (Baud:2400; Bits:$A0),
- (Baud:4800; Bits:$C0),
- (Baud:9600; Bits:$E0));
-
-
- PROCEDURE DisableInterrupts; inline($FA {cli} ); {MACROS}
- PROCEDURE EnableInterrupts; inline($FB {sti} );
-
- procedure BIOS_RS232_Init(ComPort, ComParm : Integer);
- var
- Regs : registers;
- begin
- with Regs do
- begin
- ax := ComParm and $00FF; { AH=0; AL=ComParm }
- dx := ComPort;
- Intr($14, Regs)
- end
- end;
-
- procedure Async_Isr; {INTERRUPT;}
- begin
- Inline(
- $FB/ { STI }
- { get the incomming character }
- { buffer[Buffer_head] := Chr(Port[UART_RBR + base]); }
- $8B/$16/base/ { MOV DX,base }
- $EC/ { IN AL,DX }
- $8B/$1E/Buffer_head/ { MOV BX,Buffer_head }
- $88/$87/buffer/ { MOV buffer[BX],AL }
- { Async_Buffer_NewHead := Buffer_head + 1; }
- $43/ { INC BX }
- { if Async_Buffer_NewHead > buffer_max then
- Async_Buffer_NewHead := 0; }
- $81/$FB/buffer_max/ { CMP BX,buffer_max }
- $7E/$02/ { JLE L001 }
- $33/$DB/ { XOR BX,BX }
- { if Async_Buffer_NewHead = Buffer_tail then
- Async_Buffer_Overflow := TRUE
- else }
- {L001:}
- $3B/$1E/Buffer_tail/ { CMP BX,Buffer_tail }
- $75/$08/ { JNE L002 }
- $C6/$06/Async_Buffer_Overflow/$01/ { MOV Async_Buffer_Overflow,1 }
- $90/ { NOP generated by assembler for some reason }
- $EB/$16/ { JMP SHORT L003 }
- { begin
- Buffer_head := Async_Buffer_NewHead;
- Async_Buffer_Used := Async_Buffer_Used + 1;
- if Async_Buffer_Used > Async_MaxBufferUsed then
- Async_MaxBufferUsed := Async_Buffer_Used
- end; }
- {L002:}
- $89/$1E/Buffer_head/ { MOV Buffer_head,BX }
- $FF/$06/Async_Buffer_Used/ { INC Async_Buffer_Used }
- $8B/$1E/Async_Buffer_Used/ { MOV BX,Async_Buffer_Used }
- $3B/$1E/Async_MaxBufferUsed/ { CMP BX,Async_MaxBufferUsed }
- $7E/$04/ { JLE L003 }
- $89/$1E/Async_MaxBufferUsed/ { MOV Async_MaxBufferUsed,BX }
- {L003:}
- { disable interrupts }
- $FA/ { CLI }
- { Port[$20] := $20; } { use non-specific EOI }
- $B0/$20/ { MOV AL,20h }
- $E6/$20 { OUT 20h,AL }
- )
- end; { Async_Isr }
-
- procedure Async_Init;
- begin
- Async_Open_Flag := FALSE;
- Async_Buffer_Overflow := FALSE;
- Async_Buffer_Used := 0;
- Async_MaxBufferUsed := 0;
- end; { Async_Init }
-
- procedure Async_Close;
- var
- i, m : Integer;
- begin
- if Async_Open_Flag then
- begin
-
- { disable the IRQ on the 8259 }
- DisableInterrupts;
- i := Port[I8088_IMR]; { get the interrupt mask register }
- m := 1 shl Async_Irq; { set mask to turn off interrupt }
- Port[I8088_IMR] := i or m;
-
- { disable the 8250 data ready interrupt }
- Port[UART_IER + base] := 0;
-
- { disable OUT2 on the 8250 }
- Port[UART_MCR + base] := 0;
- EnableInterrupts;
-
- SetIntVec(Async_Irq + 8,Async_OriginalVector);
-
- { re-initialize our data areas so we know the port is closed }
- Async_Open_Flag := FALSE
-
- end
- end; { Async_Close }
-
- Procedure Async_Open(ComPort : Integer;
- BaudRate : Integer;
- Parity : Char;
- WordSize : Integer;
- StopBits : Integer);
- { open a communications port }
- var
- ComParm : Integer;
- i, m : Integer;
- begin
- if Async_Open_Flag then Async_Close;
-
- if (ComPort = 4) and (Async_BIOS_Port_Table[4] <> 0) then
- Async_Port := 4;
- if (ComPort = 3) and (Async_BIOS_Port_Table[3] <> 0) then
- Async_Port := 3;
- if (ComPort = 2) and (Async_BIOS_Port_Table[2] <> 0) then
- Async_Port := 2;
- if (ComPort = 1) and (Async_BIOS_Port_Table[1] <> 0) then
- Async_Port := 1; { default to COM1 }
- base := Async_BIOS_Port_Table[Async_Port];
- Async_Irq := Hi(base) + 1;
-
- if (Port[UART_IIR + base] and $00F8)=0
- then
- begin
- Buffer_head := 0;
- Buffer_tail := 0;
- Async_Buffer_Overflow := FALSE;
-
- { Build the ComParm for RS232_Init }
- { See Technical Reference Manual for description }
-
- ComParm := $0000;
-
- { Set up the bits for the baud rate }
- i := 0;
- repeat
- i := i + 1
- until (Async_Baud_Table[i].Baud = BaudRate) or (i = Async_Num_Bauds);
- ComParm := ComParm or Async_Baud_Table[i].Bits;
-
- if Parity in ['E', 'e'] then ComParm := ComParm or $0018
- else if Parity in ['O', 'o'] then ComParm := ComParm or $0008
- else ComParm := ComParm or $0000; { default to No parity }
-
- if WordSize = 7 then ComParm := ComParm or $0002
- else ComParm := ComParm or $0003; { default to 8 data bits }
-
- if StopBits = 2 then ComParm := ComParm or $0004
- else ComParm := ComParm or $0000; { default to 1 stop bit }
-
- { use the BIOS COM port initialization routine to save typing the code }
- BIOS_RS232_Init(Async_Port - 1, ComParm);
-
- GetIntVec(Async_Irq + 8, Async_OriginalVector);
- SetIntVec(Async_Irq + 8, @Async_Isr);
-
- { read the RBR and reset any possible pending error conditions }
- { first turn off the Divisor Access Latch Bit to allow access to RBR, etc. }
-
- DisableInterrupts;
-
- Port[UART_LCR + base] := Port[UART_LCR + base] and $7F;
- { read the Line Status Register to reset any errors it indicates }
- i := Port[UART_LSR + base];
- { read the Receiver Buffer Register in case it contains a character }
- i := Port[UART_RBR + base];
-
- { enable the irq on the 8259 controller }
- i := Port[I8088_IMR]; { get the interrupt mask register }
- m := (1 shl Async_Irq) xor $00FF;
- Port[I8088_IMR] := i and m;
-
- { enable the data ready interrupt on the 8250 }
- Port[UART_IER + base] := $01; { enable data ready interrupt }
-
- { enable OUT2 on 8250 }
- i := Port[UART_MCR + base];
- Port[UART_MCR + base] := i or $08;
-
- EnableInterrupts;
- Async_Open_Flag := TRUE;
- {Async_Open := TRUE}
- end
- end; { Async_Open }
-
- procedure set_baud(r:integer);
- var rl:real; a:byte;
- begin
- if (r>=300) and (r<=9600) then begin
- rl:=115200.0/r;
- r:=trunc(rl);
- a:=port[3+base] or 128;
- port[base+3]:=a;
- port[base]:=lo(r);
- port[1+base]:=hi(r);
- port[3+base]:=a and 127;
- end;
- end;
-
- function charin:char;
- var t:char;
- begin
- if buffer_Head = buffer_Tail Then
- t:=#0
- else begin
- disableinterrupts;
- t:=buffer[buffer_Tail];
- buffer_Tail:=(buffer_Tail+1) mod (buffer_max+1);
- enableinterrupts;
- end;
- charin := t;
- end;
-
- procedure charout(c:char);
- begin
- while (port[base+5] and 32)=0 do;
- port[base]:=ord(c);
- end;
-
- function cdet:boolean;
- begin
- cdet:=(port[base+6] and 128)<>0;
- end;
- end.